package com.rpay.service.user.impl;

import com.rpay.common.dto.user.UserTokenDTO;
import com.rpay.common.enums.PcsResultCode;
import com.rpay.common.exception.TokenException;
import com.rpay.dao.user.UserTokenDao;
import com.rpay.model.user.UserTokenDO;
import com.rpay.service.user.IUserTokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import org.bson.types.ObjectId;

import java.util.Date;


/**
 * @author FangXiGang
 * @date 2018/4/21
 */
@Service
public class UserTokenServiceImpl implements IUserTokenService {

    @Value("${rpay.token.access.expired}")
    private Long accessTokenExpired;

    @Value("${rpay.token.refresh.expired}")
    private Long refreshTokenExpired;

    @Autowired
    private UserTokenDao userTokenDao;

    @Override
    public UserTokenDTO saveToken(Integer userId) {
        UserTokenDO existToken = userTokenDao.selectByUserId(userId);
        if (existToken != null) {
            Long refreshExpiredTime = refreshTokenExpired * 24 * 60 * 60 * 1000L;
            existToken.setAccessToken(new ObjectId().toString());
            existToken.setRefreshToken(new ObjectId().toString());
            existToken.setFailureTime(new Date(System.currentTimeMillis() + refreshExpiredTime));
            userTokenDao.update(existToken);
            return convertDOToDTO(existToken);
        } else {
            UserTokenDO token = generateUserToken(userId);
            userTokenDao.insert(token);
            return convertDOToDTO(token);
        }
    }

    @Override
    public UserTokenDTO modifyToken(String refreshToken) {
        long currentTime = System.currentTimeMillis();
        Long refreshExpiredTime = refreshTokenExpired * 24 * 60 * 60 * 1000L;
        UserTokenDO existToken = userTokenDao.selectByRefreshToken(refreshToken);
        //token不为null且不失效 更新accessToken;
        if (existToken != null && existToken.getFailureTime().getTime()>currentTime &&
                (existToken.getFailureTime().getTime() - currentTime <= refreshExpiredTime)) {
            existToken.setAccessToken(new ObjectId().toString());
            userTokenDao.update(existToken);
        }else {
            throw new TokenException(PcsResultCode.REFRESH_TOKEN_NOT_EXISTED);
        }
        return convertDOToDTO(existToken);
    }

    @Override
    public void deleteToken(String accessToken) {
        UserTokenDO token = userTokenDao.selectByAccessToken(accessToken);
        Long accessTokenExpiredTime = accessTokenExpired * 60 * 1000L;
        //当token不为空，且不失效时才去更新token
        if (token != null && (System.currentTimeMillis() - token.getUpdateTime().getTime() <= accessTokenExpiredTime)) {
            Long refreshExpiredTime = refreshTokenExpired * 24 * 60 * 60 * 1000L;
            token.setAccessToken(new ObjectId().toString());
            token.setRefreshToken(new ObjectId().toString());
            token.setFailureTime(new Date(System.currentTimeMillis() + refreshExpiredTime));
            userTokenDao.update(token);
        }
    }

    @Override
    public UserTokenDTO getUserToken(String accessToken) {
        UserTokenDO token = userTokenDao.selectByAccessToken(accessToken);
        Long accessTokenExpiredTime = accessTokenExpired * 60 * 1000L;
        //token为空，或者失效
        if (token == null || (System.currentTimeMillis() - token.getUpdateTime().getTime() > accessTokenExpiredTime)) {
            throw new TokenException(PcsResultCode.ACCESS_TOKEN_NOT_EXISTED);
        }
        return convertDOToDTO(token);
    }

    private UserTokenDTO convertDOToDTO(UserTokenDO userTokenDO) {
        UserTokenDTO userTokenDTO = new UserTokenDTO();
        if (userTokenDO != null) {
            userTokenDTO.setAccessToken(userTokenDO.getAccessToken());
            userTokenDTO.setUserId(userTokenDO.getUserId());
        }
        return userTokenDTO;
    }

    private UserTokenDO generateUserToken(Integer userId) {
        Long refreshExpiredTime = refreshTokenExpired * 24 * 60 * 60 * 1000L;
        UserTokenDO userTokenDO = new UserTokenDO();
        userTokenDO.setUserId(userId);
        userTokenDO.setAccessToken(new ObjectId().toString());
        userTokenDO.setRefreshToken(new ObjectId().toString());
        userTokenDO.setFailureTime(new Date(System.currentTimeMillis() + refreshExpiredTime));
        return userTokenDO;
    }
}
